﻿using Cms.Core.Application.IService;
using Cms.Core.Infrastructure;
using Cms.Core.Infrastructure.Attributes;
using Cms.Core.Infrastructure.Dependency;
using Cms.Core.Infrastructure.Extension;
using Cms.Core.Infrastructure.Log;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Reflection;


namespace Cms.Core.AspNetMvc.Mvc.Filter
{
    /// <summary>
    /// 审计
    /// </summary>
    public class AuditActionFilter : IActionFilter
    {
        public void OnActionExecuted(ActionExecutedContext context)
        {
            var actionDescriptor = context.ActionDescriptor;

            var controllerAction = actionDescriptor as ControllerActionDescriptor;

            var methodInfo = controllerAction.MethodInfo;
            var disableAuditingAttribute = methodInfo.GetCustomAttributes<DisableAuditingAttribute>()?.FirstOrDefault();
            var displayAttribute = methodInfo.GetCustomAttributes<DisplayAttribute>()?.FirstOrDefault();
            var parameterFilterAttribute = methodInfo.GetCustomAttributes<ParameterFilterAttribute>()?.FirstOrDefault();
            var actionParameter = context.FindEffectivePolicy<AuditActionParameter>()?.GetAuditActionParameter();


            if (!(context.ActionDescriptor is ControllerActionDescriptor) || disableAuditingAttribute.IsNotNull())
            {
                return;
            }
            var loggerHelper = ServiceLocator.Instance.GetService<ILoggerHelper>();
            Exception exception = null;

            var stopwatch = Stopwatch.StartNew();
            try
            {
            
                var result = context.Result;

                if (context.Exception != null && !context.ExceptionHandled)
                {
                    exception = context.Exception;
                }
            }
            catch (Exception ex)
            {

                loggerHelper.Error(ex.Message, ex);
                exception = ex;
            }
            finally
            {

                stopwatch.Stop();
                var totalMilliseconds = stopwatch.Elapsed.TotalMilliseconds.AsTo<long>();
                var auditService = ServiceLocator.Instance.GetService<IAuditService>();
                //auditService.AddAuditLog(controllerAction.ControllerTypeInfo.AsType(), controllerAction.MethodInfo, totalMilliseconds, actionParameter, parameterFilterAttribute?.GetParameterName(), displayAttribute?.DisplayName(), exception);
            }
        }

        public void OnActionExecuting(ActionExecutingContext context)
        {
            var auditActionParameter = context.FindEffectivePolicy<AuditActionParameter>();
            auditActionParameter?.SetAuditActionParameter(context.ActionArguments);
            //context.Filters.Add(new AuditActionParameter(context.ActionArguments));

        }
    }

    /// <summary>
    /// 审计Action参数
    /// </summary>
    public class AuditActionParameter : IFilterMetadata
    {
        private IDictionary<string, object> _parameter = new Dictionary<string, object>();


        public void SetAuditActionParameter(IDictionary<string, object> parameter)
        {
            _parameter = parameter;
        }

        public IDictionary<string, object> GetAuditActionParameter()
        {
            return this._parameter;
        }
    }
}
